package test.AllJoyn.ServerClient;

import org.alljoyn.bus.BusAttachment;
import org.alljoyn.bus.BusException;
import org.alljoyn.bus.BusListener;
import org.alljoyn.bus.Mutable;
import org.alljoyn.bus.ProxyBusObject;
import org.alljoyn.bus.SessionListener;
import org.alljoyn.bus.SessionOpts;
import org.alljoyn.bus.SignalEmitter;
import org.alljoyn.bus.Status;
import org.alljoyn.bus.annotation.BusSignalHandler;

import android.app.Application;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import test.AllJoyn.ServerClient.sharedName;
import test.AllJoyn.ServerClient.testAllJoynSC.Listener;
import test.AllJoyn.ServerClient.testAllJoynSC.testService;
import test.AllJoyn.ServerClient.testInterface;

public class Client extends Application{
	
	static {
		System.loadLibrary("alljoyn_java");
	}
	
	private boolean	isConnected = false;
	private int mSessionId;
	
	private BusAttachment mBusAttach;
	
	private Listener mListener;
	
	//the bus interface, share with the server side
	private testInterface mInterface;
	private testService mService;
	private ProxyBusObject mProxyBus;
	
	private Handler mBus;
	
	public Client(Listener listener)
	{
		this.mListener = listener;
		
		HandlerThread busThread = new HandlerThread("ClientBusHandler");
		busThread.start();
		mBus = new ClientBusHandler(busThread.getLooper());
		
		mBus.sendEmptyMessage(ClientBusHandler.CONNECTED);
		
	}
	
	class ClientBusHandler extends Handler
	{
		//session state
		private static final int CONNECTED = 0;
		private static final int DISCONNECTED = 1;
		private static final int JOINING = 2;
		private static final int PING = 3;
		
		public ClientBusHandler(Looper looper)
		{
			super(looper);
		}
		
		@BusSignalHandler(iface="test.AllJoyn.ServerClient.testInterface", signal="communicateText")
		public void communicateText(String msg) throws BusException 
		{
//			Toast.makeText(Client.this, msg, Toast.LENGTH_LONG).show();
			/*when the client receives the signal from the service,
			 *call the Bus Method Ping() implemented on the service side
			 *through RMI to send the message back to service */
//			Toast.makeText(Client.this, msg, Toast.LENGTH_LONG).show();
			mListener.OnComplete(msg);
//			sendMessage(msg);
		}
		
		public boolean sendMessage(Object obj)
		{
			try
			{
				if (null != mInterface)
				{
					String reply = mInterface.Ping((String)obj);
					
				}
				return true;
			}
			catch(BusException ex)
			{
				return false;
			}
		}
		
		@Override
		public void handleMessage(Message msg)
		{
			switch(msg.what)
			{
				case CONNECTED:
				{
					mBusAttach = new BusAttachment(getClass().getName(), 
							BusAttachment.RemoteMessage.Receive);
					
					mBusAttach.registerBusListener(new BusListener()
					{
						@Override
						public void foundAdvertisedName(String Name, short transport, String name)
						{
							Message msg = obtainMessage(JOINING, Name);
							sendMessage(msg);
						}
					});
					
					Status status = mBusAttach.connect();
					if (Status.OK != status)
					{
						logStatus("client:BusAttachment.connect()", status);
						return;
					}
					
					status = mBusAttach.registerSignalHandlers(this);
					if (Status.OK != status)
					{
						logStatus("Client:registerSignal", status);
						return;
					}
					
					status = mBusAttach.findAdvertisedName(sharedName.Service_name);
					if (Status.OK != status)
					{
						logStatus("Client:findAdvertiseName()", status);
						return;
					}
					
					
					break;
				}
				case JOINING:
				{
					SessionOpts sessionOpts = new SessionOpts();
					Mutable.IntegerValue sessionId = new Mutable.IntegerValue();
					
					Status status = mBusAttach.joinSession((String)msg.obj, 
														   sharedName.Contact_Port, 
														   sessionId, 
														   sessionOpts, 
														   new SessionListener());
					
					if (Status.OK == status)
					{
						logStatus("Client:joinSession()", status);
//						mProxyBus = mBusAttach.getProxyBusObject(sharedName.Service_name, 
//								"/service", 
//								sessionId.value, 
//								new Class<?>[]{testInterface.class});
//						
//						mInterface = mProxyBus.getInterface(testInterface.class);
						
//						SignalEmitter emitter = new SignalEmitter(mService, 
//																  mSessionId, 
//																  SignalEmitter.GlobalBroadcast.Off);
//
//						mInterface = emitter.getInterface(testInterface.class);
						
						
						isConnected = true;
					}
					break;
				}
				case DISCONNECTED:
				{
					if (true == isConnected)
					{
						Status status = mBusAttach.leaveSession(mSessionId);
					}
					mBusAttach.disconnect();
					getLooper().quit();
					break;
				}
				default:
				{
					break;
				}
			}
		}
	}
		
	
	private void logStatus(String msg, Status status)
	{
		String log = String.format("%s : %s", msg, status);
		if (status == Status.OK)
		{
			Log.i(sharedName.TAG, log);
		}
		else
		{
//			Toast.makeText(Client.this, log, Toast.LENGTH_LONG).show();
			Log.e(sharedName.TAG, log);
		}
	}
	
	

}
